/**
 * @file   Ufo.java
 * @author Enrique Madrid <emadridm@gmail.com>
 * @date   Mon Jul 16 18:31:27 2007
 *
 * @brief 
 *
 */

package com.myt.matp.core;

import com.myt.matp.MATlet;
import com.myt.matp.utils.Queue;
import com.myt.matp.utils.Stack;

import java.util.*;

public abstract class Ufo extends Thread {

    // Message queue size
    private static final int QUEUE_INIT_SIZE = 4;

    // Ufo Status
    protected static final int STATUS_STOPED = 1;
    protected static final int STATUS_RUNING = 2;
    protected static final int STATUS_WAITING = 3;

    // Messages
    public static final int MSG_QUIT = 1;
    public static final int MSG_WAIT = 2;
    public static final int MSG_TOUT = 3;
    public static final int MSG_USER = 4;
    
    protected MATlet m_MATlet = null;
    protected int m_Status = STATUS_STOPED;
    private long m_Wait = 0;

    // Tareas
    private Queue m_Pending = new Queue(QUEUE_INIT_SIZE);
    private Stack m_Recycle = new Stack(QUEUE_INIT_SIZE);

    /**
     * Constructor.
     *
     * @param m Referencia a un objeto del tipo MATlet.
     *
     * @return Devuelve una referencia a un objeto del tipo Ufo.
     */
    public Ufo(MATlet m) {
        m_MATlet = m;
    }

    public final int getStatus() {
	return m_Status;
    }

    public final void setWait(long w) {
	m_Wait = w;
	postMessage(createMessage(this.MSG_WAIT));
    }

    public final long getWait() {
	return m_Wait;
    }

    public final Msg createMessage(int id) {
	Msg msg = (Msg)m_Recycle.get();
	if (msg == null) {
	    msg = new Msg();
	}
	msg.set(null);
	msg.setId(id);
	return msg;
    }
        
    public synchronized final void postMessage(Msg msg) {
	m_Pending.put(msg);
	notify();
    }

    public final void postMsgQuit() {
	postMessage(createMessage(this.MSG_QUIT));
    }
           
    public void run() {
        Msg msg;
	boolean stop = false;
	long time1;

        //#ifdef DEBUG_UFO
        //# System.out.println(getClass().getName() + ".run() {");
        //#endif
	time1 = System.currentTimeMillis();
        while(!stop) {

	    //#ifdef DEBUG_UFO
	    //# System.out.println("\trunning ...");
	    //#endif
	    
	    m_Status  = STATUS_RUNING;

            msg = (Msg)m_Pending.get();

	    while(msg != null) {

		try {

		    switch (msg.getId()) {
		    case Ufo.MSG_QUIT:
			stop = true;
			break;
		    default:
			//#ifdef DEBUG_UFO
			//# System.out.println("\tcalling run(Msg)");
			//#endif
			run(msg);
			break;
		    }
		    
		} catch (Exception e) {
		    e.printStackTrace();
		}
		
		m_Recycle.put(msg);
                msg = (Msg)m_Pending.get();
            }

	    synchronized (this) { 
		try {
		    if (!stop) {
			//#ifdef DEBUG_UFO
			//# System.out.println("\twaiting " + m_Wait + " ms");
			//#endif
			m_Status = STATUS_WAITING;
			time1 = System.currentTimeMillis();
			//#ifdef DEBUG_UFO
			//# System.out.println("\ttime1 = " + time1);
			//#endif
			wait(m_Wait);
		    }
		} catch(InterruptedException e) {

		} finally {
		    //#ifdef DEBUG_UFO
		    //# System.out.println("\tSystem.currentTimeMillis() = " + System.currentTimeMillis());
		    //#endif
		    if ((m_Wait > 0) &&
			(System.currentTimeMillis() - time1 >= m_Wait)) {
			postMessage(createMessage(this.MSG_TOUT));
		    }
		    
		};
	    }
        }

        //#ifdef DEBUG_UFO
        //# System.out.println("}");
        //#endif
	m_Status = STATUS_STOPED;
    }

    protected abstract void run(final Msg msg);        
}
